package security.core.filter;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.springframework.web.filter.GenericFilterBean;

import security.debug.RBACLogger;

public class RBACFilterChainProxy extends GenericFilterBean {
	private SessionContextFilter sessionContextFilter;
	private LogoutFilter logoutFilter;
	private LoginFilter loginFilter;
	private PrivilegeFilter privilegeFilter;
	private List<String> ignoreList;

	@Override
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException,
			ServletException {
		if (RBACLogger.debug()) {
			RBACLogger.log("RBACFilterChainProxy#doFilter is called!");
		}
		
		// check is the request is within the ignore list
		if (isIgnoreRequest(request)) {
			// ignore the request and go back to the chain
			chain.doFilter(request, response);
		} else {
			// filter the request
			RBACFilterChain actualFilterChain = new RBACFilterChain(getOrderedFilters(), chain);
			actualFilterChain.doFilter(request, response);
		}
	}
	
	private Boolean isIgnoreRequest(ServletRequest request) {
		if (RBACLogger.debug()) {
			RBACLogger.log("RBACFilterChainProxy#isIgnoreRequest is called!");
		}
		String requestURL = ((HttpServletRequest)request).getRequestURI();
		// travel the ignore list to check if there is matched pattern
		for (String pattern : ignoreList) {
			if (RBACLogger.debug()) {
				RBACLogger.log("pattern is:" + pattern + " and request url is:" + requestURL);
			}
			if (Pattern.matches(pattern, requestURL)) {
				return true;
			}
		}
		return false;
	}
	
	private List<Filter> getOrderedFilters() {
		List<Filter> filters = new ArrayList<Filter>();
		filters.add(sessionContextFilter);
		filters.add(logoutFilter);
		filters.add(loginFilter);
		filters.add(privilegeFilter);
		return filters;
	}

	// Setter of filters
	public void setSessionContextFilter(SessionContextFilter sessionContextFilter) {
		this.sessionContextFilter = sessionContextFilter;
	}

	public void setLogoutFilter(LogoutFilter logoutFilter) {
		this.logoutFilter = logoutFilter;
	}

	public void setLoginFilter(LoginFilter loginFilter) {
		this.loginFilter = loginFilter;
	}

	public void setPrivilegeFilter(PrivilegeFilter privilegeFilter) {
		this.privilegeFilter = privilegeFilter;
	}

	public void setIgnoreList(List<String> ignoreList) {
		this.ignoreList = ignoreList;
	}	
}
